from typing import Dict, List, Optional
import json
import re
from datetime import datetime
from bs4 import BeautifulSoup
from loguru import logger

from .BaseParser import BaseParser

import os
from datetime import datetime

# 在类的初始化方法中添加
class AssetRestructureParser(BaseParser):
    """资产重组数据解析器"""
    
    def __init__(self):
        super().__init__()
        self.base_url = "https://data.eastmoney.com/notices/hsa/6.html"
        self.category = "资产重组"
        # 使用绝对路径确保调试目录位置正确
        self.debug_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "debug_pages")  # 调试页面保存目录
        # 创建调试目录（如果不存在）
        if not os.path.exists(self.debug_dir):
            try:
                os.makedirs(self.debug_dir)
                logger.info(f"创建调试目录成功: {self.debug_dir}")
            except Exception as e:
                logger.error(f"创建调试目录失败: {str(e)}")

    def _save_page_for_debug(self, html_content: str, url: str) -> str:
        """保存页面内容用于调试
        
        Args:
            html_content: 页面HTML内容
            url: 页面URL
        
        Returns:
            str: 保存的文件路径
        """
        try:
            # 确保调试目录存在
            if not os.path.exists(self.debug_dir):
                try:
                    os.makedirs(self.debug_dir)
                    logger.info(f"创建调试目录成功: {self.debug_dir}")
                except Exception as e:
                    logger.error(f"创建调试目录失败: {str(e)}")
                    return ""
            
            # 生成唯一的文件名
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S_%f')
            # 从URL提取部分作为文件名的一部分
            url_part = url.replace('https://', '').replace('/', '_').replace(':', '_')[:50] if url else "unknown_url"
            filename = f"{timestamp}_{url_part}.html"
            file_path = os.path.join(self.debug_dir, filename)
            
            # 保存页面内容
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(html_content)
                
            logger.info(f"调试页面已保存至: {file_path}")
            return file_path
        except Exception as e:
            logger.error(f"保存调试页面失败: {str(e)}")
            return ""

    # 修改parse方法，添加保存页面功能
    def parse(self, html_content: str, url: str = "") -> List[Dict]:
        """解析HTML内容，提取资产重组信息
        
        Args:
            html_content: 要解析的HTML内容
            url: 页面URL（用于调试）
            
        Returns:
            List[Dict]: 解析后的新闻数据列表
        """
        # 保存页面用于调试
        self._save_page_for_debug(html_content, url)
        
        # 原有解析逻辑
        soup = BeautifulSoup(html_content, 'html.parser')
        news_list = []
        
        # 尝试从JSON数据中提取
        json_news = self._extract_from_json(soup)
        if json_news:
            news_list.extend(json_news)
        
        # 尝试从表格中提取
        table_news = self._extract_from_table(soup)
        if table_news:
            news_list.extend(table_news)
        
        # 尝试从页面文本中提取
        text_news = self._extract_from_page_text(soup)
        if text_news:
            news_list.extend(text_news)
        
        # 去重处理
        news_list = self._remove_duplicates(news_list)
        
        logger.info(f"总共提取到 {len(news_list)} 条资产重组新闻")
        return news_list
    
    def _get_json_patterns(self) -> List[str]:
        """获取资产重组数据的JSON提取模式"""
        return [
            r'var\s+pagedata\s*=\s*(\{.*?\})\s*;',  # pagedata变量
            r'"list"\s*:\s*\{\s*"data"\s*:\s*\{\s*"list"\s*:\s*(\[.*?\])\s*\}\s*\}',  # 嵌套列表结构
            r'var\s+(?:data|list|noticeData|pageData|hsaData)\s*=\s*(\[.*?\]);',
            r'"(?:data|list|noticeList|pageList|hsaList)"\s*:\s*(\[.*?\])',
            r'noticeData\s*[=:]\s*(\[.*?\])',
            r'hsaData\s*[=:]\s*(\[.*?\])',  # 资产重组数据变量
            r'pageData\s*[=:]\s*(\{.*?\})',  # 页面数据
            r'window\.pageData\s*=\s*(\{.*?\});',  # 全局页面数据
            r'window\.hsaData\s*=\s*(\[.*?\]);',  # 全局资产重组数据
            r'var\s+hsaData\s*=\s*(\[.*?\]);',  # 资产重组数据变量
        ]
    
    def _get_table_selectors(self) -> List[str]:
        """获取资产重组数据表格选择器"""
        return [
            '.dataview tr',  # 数据视图行
            'table tbody tr',  # 表格数据行
            '.dataview-body tr',  # 数据视图主体
            '.table-responsive tbody tr',  # 响应式表格
            '.list-table tbody tr',  # 列表表格
            '[data-code]',  # 带有股票代码的元素
            '.notices-item',  # 公告项
            '.tbody tr',  # 另一种表格结构
            'tr[data-id]',  # 带ID的表格行
            '.table tbody tr',  # 标准表格
            '.dataview tbody tr',  # 数据视图表格
            '#table_wrapper tbody tr',  # 表格包装器
            '.table-list tbody tr',  # 列表表格
            '.data-table tbody tr',  # 数据表格
        ]
    
    def _is_relevant_title(self, title_text: str) -> bool:
        """判断标题是否与资产重组相关"""
        keywords = ['资产重组', '公告', '重组', '收购', '合并', '转让']
        return any(keyword in title_text for keyword in keywords)
    
    def _extract_title_and_link_from_element(self, element) -> tuple:
        """从元素中提取标题和链接
        
        Args:
            element: BeautifulSoup元素对象
        
        Returns:
            tuple: (标题文本, 链接URL, notice_id)
        """
        title_text = ""
        link_href = ""
        notice_id = ""
        
        # 首先查找所有的链接元素
        link_elements = element.find_all('a')
        for link in link_elements:
            href = link.get('href', '')
            link_text = link.get_text(strip=True)
            
            # 如果链接文本包含相关关键词，优先使用
            if link_text and len(link_text) > 5 and ('公告' in link_text or '重组' in link_text):
                title_text = link_text
                # 处理链接
                if href:
                    if href.startswith('/'):
                        link_href = f"https://data.eastmoney.com{href}"
                    elif href and not href.startswith('http'):
                        link_href = f"https://data.eastmoney.com/{href}"
                    else:
                        link_href = href
                    
                    # 尝试从链接中提取notice_id
                    notice_id_match = re.search(r'/([A-Za-z0-9]+)\.html$', href)
                    if notice_id_match:
                        notice_id = notice_id_match.group(1)
                break
        
        # 如果没有找到链接中的标题，查找其他标题元素
        if not title_text:
            title_elements = element.find_all(['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'strong', 'b', 'td', 'div', 'span'])
            for title_elem in title_elements:
                candidate_text = title_elem.get_text(strip=True)
                if candidate_text and len(candidate_text) > 5 and ('公告' in candidate_text or '重组' in candidate_text or '收购' in candidate_text):
                    title_text = candidate_text
                    # 尝试从标题元素的父元素或兄弟元素中查找链接
                    if not link_href:
                        # 检查父元素是否是链接
                        parent_links = title_elem.find_parents('a')
                        if parent_links:
                            href = parent_links[0].get('href', '')
                            if href:
                                if href.startswith('/'):
                                    link_href = f"https://data.eastmoney.com{href}"
                                elif href and not href.startswith('http'):
                                    link_href = f"https://data.eastmoney.com/{href}"
                                else:
                                    link_href = href
                                
                                # 尝试从链接中提取notice_id
                                notice_id_match = re.search(r'/([A-Za-z0-9]+)\.html$', href)
                                if notice_id_match:
                                    notice_id = notice_id_match.group(1)
                        # 检查兄弟元素是否包含链接
                        if not link_href:
                            sibling_links = title_elem.find_next_siblings('a')
                            for sibling_link in sibling_links:
                                href = sibling_link.get('href', '')
                                if href:
                                    if href.startswith('/'):
                                        link_href = f"https://data.eastmoney.com{href}"
                                    elif href and not href.startswith('http'):
                                        link_href = f"https://data.eastmoney.com/{href}"
                                    else:
                                        link_href = href
                                        
                                        # 尝试从链接中提取notice_id
                                        notice_id_match = re.search(r'/([A-Za-z0-9]+)\.html$', href)
                                        if notice_id_match:
                                            notice_id = notice_id_match.group(1)
                                            break
            # 特殊处理：如果找到带有data-href属性的元素，也提取链接
            if not link_href:
                data_href_elem = element.find(attrs={'data-href': True})
                if data_href_elem:
                    href = data_href_elem.get('data-href', '')
                    if href:
                        if href.startswith('/'):
                            link_href = f"https://data.eastmoney.com{href}"
                        elif href and not href.startswith('http'):
                            link_href = f"https://data.eastmoney.com/{href}"
                        else:
                            link_href = href
                            
                            # 尝试从链接中提取notice_id
                            notice_id_match = re.search(r'/([A-Za-z0-9]+)\.html$', href)
                            if notice_id_match:
                                notice_id = notice_id_match.group(1)
        
        return title_text, link_href, notice_id
    
    def _extract_from_element(self, element) -> Dict:
        """从资产重组表格元素中提取信息"""
        try:
            # 提取表格单元格
            cells = element.find_all(['td', 'th'])
            if not cells or len(cells) < 2:
                # 如果没有td/th，尝试查找其他元素
                text_elements = element.find_all(['div', 'span', 'a'])
                if text_elements:
                    # 提取所有文本内容
                    all_text = element.get_text(strip=True)
                    if len(all_text) > 10 and ('重组' in all_text or '公告' in all_text or '合并' in all_text):
                        # 生成一个基础的公告项
                        restructure_data = {
                            'SECURITY_NAME_ABBR': all_text[:20],  # 取前20个字符作为名称
                            'SECURITY_CODE': '',
                            'NOTICE_DATE': '',  # 需要从页面爬取
                            'EVENT_TYPE': '公告信息',
                            'TITLE': all_text[:50],  # 使用文本前50个字符作为标题
                            'LINK': ''
                        }
                        return self._convert_data_to_news(restructure_data)
                return None
            
            # 处理有td/th的情况
            # 提取文本内容，去除空格
            cell_texts = [cell.get_text(strip=True) for cell in cells]
            
            # 过滤空内容
            cell_texts = [text for text in cell_texts if text]
            
            if len(cell_texts) < 2:
                return None
            
            # 常见的公告表格格式：股票名称、股票代码、公告日期、事件类型等
            stock_name = cell_texts[0] if len(cell_texts) > 0 else ''
            stock_code = cell_texts[1] if len(cell_texts) > 1 else ''
            notice_date = cell_texts[2] if len(cell_texts) > 2 else ''
            event_type = cell_texts[3] if len(cell_texts) > 3 else '公告'
            
            # 尝试从页面中提取公告标题和链接
            title, link, notice_id = self._extract_title_and_link_from_element(element)
            if not title:
                title = f"{stock_name}({stock_code}){event_type}公告" if stock_name and stock_code else f"{event_type}公告"
            
            # 检查股票代码格式（应该是6位数字）
            if not re.match(r'\d{6}', stock_code):
                # 如果第二列不是股票代码，重新调整
                if len(cell_texts) >= 3:
                    # 尝试找到股票代码
                    for i, text in enumerate(cell_texts):
                        if re.match(r'\d{6}', text):
                            stock_code = text
                            # 调整其他字段
                            if i > 0:
                                stock_name = cell_texts[i-1] if i-1 < len(cell_texts) else stock_name
                            if i+1 < len(cell_texts):
                                notice_date = cell_texts[i+1]
                            break
                else:
                    stock_code = ''
            
            # 检查数据有效性
            if not stock_name or len(stock_name) < 2:
                return None
            
            # 检查是否与资产重组相关
            content_text = ' '.join(cell_texts).lower()
            restructure_keywords = ['重组', '合并', '收购', '资产', '股权', '转让']
            
            is_restructure_related = any(keyword in content_text for keyword in restructure_keywords)
            
            if is_restructure_related:
                event_type = '资产重组'
            else:
                # 即使不直接相关，也作为公告信息返回
                event_type = '公告信息'
            
            # 生成资产重组数据
            restructure_data = {
                'SECURITY_NAME_ABBR': stock_name,
                'SECURITY_CODE': stock_code,
                'NOTICE_DATE': notice_date,
                'EVENT_TYPE': event_type,
                'TITLE': title,
                'LINK': link,
                'notice_id': notice_id  # 添加notice_id字段
            }
            
            return self._convert_data_to_news(restructure_data)
            
        except Exception as e:
            logger.debug(f"提取资产重组表格数据失败: {str(e)}")
            return None
    
    # 修改_extract_from_page_text函数，添加从页面文本中提取链接的逻辑
    def _extract_from_page_text(self, soup) -> List[Dict]:
        """从页面文本中提取资产重组信息"""
        news_list = []
        try:
            page_text = soup.get_text()
            
            # 查找包含股票代码和重组关键词的文本
            stock_pattern = r'([0-9]{6})[^\n]*?(重组|合并|收购|资产|股权)'
            matches = re.findall(stock_pattern, page_text)
            
            for match in matches:
                stock_code = match[0]
                event_type = match[1]
                
                # 尝试从页面中提取链接和标题
                title = f"{stock_code} - {event_type}公告"
                link = ""
                notice_id = ""
                
                # 查找所有链接元素，尝试找到与当前股票代码相关的链接
                link_elements = soup.find_all('a')
                for a_elem in link_elements:
                    href = a_elem.get('href', '')
                    link_text = a_elem.get_text(strip=True)
                    
                    if href and (stock_code in href or stock_code in link_text or event_type in link_text):
                        # 处理链接
                        if href.startswith('/'):
                            link = f"https://data.eastmoney.com{href}"
                        elif href and not href.startswith('http'):
                            link = f"https://data.eastmoney.com/{href}"
                        else:
                            link = href
                        
                        # 尝试从链接中提取notice_id
                        notice_id_match = re.search(r'/([A-Za-z0-9]+)\.html$', href)
                        if notice_id_match:
                            notice_id = notice_id_match.group(1)
                        
                        # 如果链接文本不为空，使用链接文本作为标题
                        if link_text and len(link_text) > 5:
                            title = link_text
                        break
                
                # 生成基础的资产重组新闻
                restructure_data = {
                    'SECURITY_NAME_ABBR': f'股票{stock_code}',
                    'SECURITY_CODE': stock_code,
                    'NOTICE_DATE': '',  # 需要从页面爬取
                    'EVENT_TYPE': f'{event_type}公告',
                    'TITLE': title,  # 使用提取到的标题
                    'LINK': link,  # 使用提取到的链接
                    'notice_id': notice_id  # 添加notice_id字段
                }
                
                restructure_news = self._convert_data_to_news(restructure_data)
                if restructure_news:
                    news_list.append(restructure_news)
            
            if news_list:
                logger.info(f"从页面文本中提取到 {len(news_list)} 条资产重组信息")
        except Exception as e:
            logger.debug(f"从页面文本提取资产重组信息失败: {str(e)}")
        
        return news_list
    
    def _convert_data_to_news(self, restructure_item: Dict) -> Dict:
        """将资产重组数据转换为新闻格式"""
        try:
            # 提取常见字段，支持新的数据结构
            stock_name = ""
            stock_code = ""
            notice_date = ""
            event_type = "资产重组"
            notice_id = ""  # 添加公告ID字段
            
            # 处理新的数据结构
            if 'codes' in restructure_item and restructure_item['codes']:
                # 新结构：codes数组包含股票信息
                code_info = restructure_item['codes'][0]
                stock_name = code_info.get('short_name', code_info.get('name', ''))
                stock_code = code_info.get('stock_code', code_info.get('code', ''))
            else:
                # 旧结构
                stock_name = restructure_item.get('SECURITY_NAME_ABBR', restructure_item.get('name', ''))
                stock_code = restructure_item.get('SECURITY_CODE', restructure_item.get('code', ''))
            
            # 提取公告链接（如果存在）
            link = restructure_item.get('link', restructure_item.get('LINK', ''))
            
            # 提取公告ID（如果存在）
            notice_id = restructure_item.get('ARTICLEID', restructure_item.get('notice_id', ''))
            
            # 提取公告日期
            notice_date = restructure_item.get('notice_date', restructure_item.get('NOTICE_DATE', ''))
            
            # 提取公告标题
            title = restructure_item.get('title', restructure_item.get('TITLE', ''))
            
            # 如果没有标题，生成默认标题：证券代码、证券名称、公告内容
            if not title:
                title = f"{stock_code} {stock_name} - {event_type}公告"
            else:
                # 如果标题不包含股票信息，添加股票信息
                if stock_code and stock_name and (stock_code not in title or stock_name not in title):
                    title = f"{stock_code} {stock_name} - {title}"
            
            # 如果notice_date为空，尝试从页面中提取日期
            if not notice_date:
                # 尝试从标题或其他字段中提取日期
                date_patterns = [
                    r'(\d{4}-\d{2}-\d{2})',
                    r'(\d{4}/\d{2}/\d{2})',
                    r'(\d{4}年\d{1,2}月\d{1,2}日)',
                    r'(\d{1,2}月\d{1,2}日)'
                ]
                
                for pattern in date_patterns:
                    match = re.search(pattern, title)
                    if match:
                        notice_date = match.group(1)
                        break
                
                # 如果还是没有找到日期，不兜底，保持为空，交由上层处理
                if not notice_date:
                    notice_date = ''
            
            # 如果title为空，尝试使用页面标题
            if not title:
                # 这里可以传入页面标题，但需要修改方法签名
                # 暂时使用默认标题
                title = f"{stock_name}({stock_code}){event_type}公告" if stock_name and stock_code else f"{event_type}公告"
            
            # 提取公告类型
            if 'columns' in restructure_item and restructure_item['columns']:
                columns = restructure_item['columns']
                if isinstance(columns, list) and len(columns) > 0:
                    event_type = columns[0].get('column_name', event_type)
            
            # 生成新闻摘要
            summary = f"东方财富数据显示，{stock_name}"
            if notice_date:
                summary += f"于{notice_date.split(' ')[0]}"  # 只取日期部分
            summary += f"发布{event_type}公告。"
            
            # 生成URL - 优先使用提取到的链接，否则使用正确的东方财富新闻链接格式
            url = ""
            if link:
                # 使用提取到的链接
                url = link           
            
            news_item = {
                'title': title,
                'url': url,
                'source': '东方财富',
                'publish_time': self._normalize_time(notice_date),
                'summary': summary,
                'category': self.category,
                'keywords': ['资产重组', '公告', stock_code, stock_name, event_type],
                'crawl_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                'stock_codes': json.dumps([stock_code]) if stock_code else None,
                'stock_name': stock_name,
                'event_type': event_type
            }
            
            return news_item
            
        except Exception as e:
            logger.debug(f"转换资产重组数据失败: {str(e)}")
    
    